﻿using System.Security.Cryptography;
using System.Text;

namespace Core.Common.Security;

/// <summary>
/// 为 string 提供 PBKDF2-HMAC-SHA256 的扩展方法。
/// </summary>
public static class StringPasswordExtensions
{
    private const int SaltSize = 16;        // 128-bit salt
    private const int KeySize = 32;        // 256-bit key
    private const int Iterations = 100_000; // NIST 推荐 ≥100k

    /// <summary>
    /// 对明文密码进行哈希，返回 "iter:salt:hash" 格式的字符串。
    /// </summary>
    public static string HashPassword(this string password)
    {
        if (string.IsNullOrWhiteSpace(password))
            throw new ArgumentException("密码不能为空");

        byte[] salt = RandomNumberGenerator.GetBytes(SaltSize);
        byte[] hash = Rfc2898DeriveBytes.Pbkdf2(
            Encoding.UTF8.GetBytes(password),
            salt,
            Iterations,
            HashAlgorithmName.SHA256,
            KeySize);

        return $"{Iterations}:{Convert.ToBase64String(salt)}:{Convert.ToBase64String(hash)}";
    }

    /// <summary>
    /// 验证密码是否匹配已存储的哈希字符串。
    /// </summary>
    public static bool VerifyPassword(this string password, string storedHash)
    {
        if (string.IsNullOrWhiteSpace(password) || string.IsNullOrWhiteSpace(storedHash))
            return false;

        var parts = storedHash.Split(':', 3);
        if (parts.Length != 3) return false;

        if (!int.TryParse(parts[0], out int iterations)) return false;
        byte[] salt = Convert.FromBase64String(parts[1]);
        byte[] expectedHash = Convert.FromBase64String(parts[2]);

        byte[] actualHash = Rfc2898DeriveBytes.Pbkdf2(
            Encoding.UTF8.GetBytes(password),
            salt,
            iterations,
            HashAlgorithmName.SHA256,
            expectedHash.Length);

        return CryptographicOperations.FixedTimeEquals(actualHash, expectedHash);
    }
}
